package org.shoukaiseki.aliyun.oss.service.impl;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.shoukaiseki.aliyun.oss.config.AliyunOSSCoreProperties;
import org.shoukaiseki.aliyun.oss.config.BaseOSSPathProperties;
import org.shoukaiseki.aliyun.oss.config.BaseOSSProperties;
import org.shoukaiseki.aliyun.oss.constant.AliyunOSSCoreConfigConstants;
import org.shoukaiseki.aliyun.oss.domain.StsInfo;
import org.shoukaiseki.aliyun.oss.exception.AliyunOSSException;
import org.shoukaiseki.aliyun.oss.service.AliyunOSSManagerService;
import org.shoukaiseki.common.utils.ContentTypeUtils;
import org.shoukaiseki.logging.FixedLoggers;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.UUID;

@Service
public class AliyunOSSManagerImpl  implements AliyunOSSManagerService {

    final Logger logger= FixedLoggers.ALIYUN_OSS_LOGGER;


    @Resource(name = "ossClient")
    OSSClient ossClient;

    @Resource(name = "urlMakeOSSClient")
    OSSClient urlMakeOSSClient;

    @Resource
    AliyunOSSCoreProperties aliyunOSSCoreProperties;


    @Resource
    BaseOSSPathProperties baseOSSPathProperties;




    public StsInfo getAliyunStsInfo( String ossName) throws ClientException {

        if (logger.isDebugEnabled()) {
//            logger.debug("aliyunOSSCoreProperties="+ JSONObject.toJSONString(aliyunOSSCoreProperties));
//            logger.debug("aliyunOSSCoreProperties.getAccessKeyId()="+aliyunOSSCoreProperties.getAccessKeyId());
//            logger.debug("aliyunOSSCoreProperties.getSecretAccessKey()="+aliyunOSSCoreProperties.getSecretAccessKey());
//            logger.debug("111agt");
        }

        // 构造default profile（参数留空，无需添加region ID）
        IClientProfile profile = DefaultProfile.getProfile("", aliyunOSSCoreProperties.getAccessKeyId(), aliyunOSSCoreProperties.getSecretAccessKey());
        // 用profile构造client
        DefaultAcsClient client = new DefaultAcsClient(profile);
        AssumeRoleRequest request = new AssumeRoleRequest();


        String stsEndpoint=aliyunOSSCoreProperties.getSysEndpoint();
//        request.setActionName("sts:AssumeRole");
        request.setSysEndpoint(stsEndpoint);
        request.setSysMethod(MethodType.POST);
        request.setRoleArn(aliyunOSSCoreProperties.getRoleArn());
        request.setRoleSessionName(aliyunOSSCoreProperties.getRoleSessionName());
        request.setDurationSeconds(1500L);
        String policy = aliyunOSSCoreProperties.getPolicy();
        policy=policy.replaceAll("\\$\\{bucketName\\}",aliyunOSSCoreProperties.getBucketName());
        policy=policy.replaceAll("\\$\\{ossName\\}",ossName);
        request.setPolicy(policy);
        final AssumeRoleResponse response = client.getAcsResponse(request);


        StsInfo stsInfo = new StsInfo();


        AssumeRoleResponse.Credentials credentials = response.getCredentials();
        stsInfo.setAccessKeyId(credentials.getAccessKeyId());
        stsInfo.setAccessKeySecret(credentials.getAccessKeySecret());
        stsInfo.setBucket(aliyunOSSCoreProperties.getBucketName());
        stsInfo.setEndpoint(aliyunOSSCoreProperties.getEndpoint());
        stsInfo.setStsToken(credentials.getSecurityToken());

        return stsInfo;
    }



    public StsInfo baseGetStsInfo( BaseOSSProperties baseOSSProperties,String fileName,boolean customFileName) throws Exception {
        String newFileName;
        if(customFileName){
            newFileName=fileName;
        }else{
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            newFileName = uuid+fileName.substring(fileName.lastIndexOf("."));
        }
        String ossFileName = newFileName;
        if(baseOSSProperties.getSavePath()==null||baseOSSProperties.getSavePath().trim().isEmpty()){
            throw new RuntimeException("配置文件的savePath路径不能为空,不允许在主目录存储文件");
        }
        ossFileName=baseOSSProperties.getSavePath()+"/"+newFileName;
        StsInfo stsInfo=getAliyunStsInfo(ossFileName);
        stsInfo.setOssName(ossFileName);
        if(fileName.contains(".")){
            stsInfo.setFileName(fileName.substring(0,fileName.lastIndexOf(".")));
        }else{
            stsInfo.setFileName(fileName);
        }

        String url = generateUrl(aliyunOSSCoreProperties.getEndpoint(), aliyunOSSCoreProperties.getBucketName(), ossFileName);

        stsInfo.setUrl(url);

        return stsInfo;
    }

    @Override
    public StsInfo getStsInfo( BaseOSSProperties baseOSSProperties, String fileName,boolean customFileName) throws Exception {
        return baseGetStsInfo(baseOSSProperties,fileName,customFileName);
    }

    @Override
    public StsInfo getStsInfo(BaseOSSProperties baseOSSProperties, String fileName) throws Exception {
        return baseGetStsInfo(baseOSSProperties,fileName,false);
    }

    @Override
    public StsInfo getStsInfo(String fileName) throws Exception {
        return baseGetStsInfo(this.baseOSSPathProperties,fileName,false);
    }


    @Override
    public String createBucketName(String bucketName) {
        //存储空间
        final String bucketNames=bucketName;
        if(!ossClient.doesBucketExist(bucketName)){
            //创建存储空间
            Bucket bucket=ossClient.createBucket(bucketName);
            logger.info("创建存储空间成功");
            return bucket.getName();
        }
        return bucketNames;
    }

    @Override
    public void deleteBucket(String bucketName) {
        ossClient.deleteBucket(bucketName);
        logger.info("删除" + bucketName + "Bucket成功");
    }

    @Override
    public String createPath(String bucketName, String path) {
        //文件夹名
        final String keySuffixWithSlash =path;
        //判断文件夹是否存在，不存在则创建
        if(!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)){
            //创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            logger.info("创建文件夹成功");
            //得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir=object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    @Override
    public void deleteFile(String bucketName, String path, String key) {
        ossClient.deleteObject(bucketName, path + key);
        logger.info("删除{}下的文件{}{}成功",bucketName,path,key);

    }

    @Override
    public String[] uploadFile(InputStream inputStream, String bucketName, String path, String fileName) {
        String[] resultStr = new String[2];
        try {
            //创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            //上传的文件的长度
            metadata.setContentLength(inputStream.available());
            //指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            //指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            //指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            //文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            //如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(ContentTypeUtils.getContentType(fileName));
            //指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename=" + fileName);
            //上传文件   (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, path + fileName, inputStream,metadata);
            //解析结果
            resultStr[0] = putResult.getETag();
            resultStr[1] = path+fileName;
        } catch (Throwable e) {
            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
            throw new AliyunOSSException("上传阿里云OSS服务器异常");
        }
//        finally {
//            ossClient.shutdown();
//        }
        return resultStr;
    }

    @Override
    public String getUrl(String bucketName, String fileName) {
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        Date expiration = AliyunOSSCoreConfigConstants.OSS_EXPIRATION_TIME;
        // 生成URL
        URL url = urlMakeOSSClient.generatePresignedUrl(bucketName, fileName, expiration);
        if (url != null) {
            return url.toString();
        }
        throw new AliyunOSSException("获取URL地址异常");
    }

    /**
     * 生成oss访问URL
     * @param ossFilename
     * @return
     */
    public String generateUrl(String endpoint,String bucketName, String ossFilename) {
        StringBuilder sb=new StringBuilder();
        sb.append("https://");
        sb.append(bucketName);
        sb.append(".");
        sb.append(endpoint);
        sb.append("/");
        sb.append(ossFilename);
        return sb.toString();
    }
}
